package com.javabi.common.concurrent;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * A simple atomic barrier that used to prevent threads from proceeding until the barrier is released.
 */
public class AtomicBarrier {

	private final AtomicBoolean blocking = new AtomicBoolean(true);
	private final Lock lock = new ReentrantLock();
	private final Condition condition = lock.newCondition();

	public void reset() {
		lock.lock();
		try {
			if (blocking.compareAndSet(false, true)) {
				condition.signalAll();
			}
		} finally {
			lock.unlock();
		}
	}

	public boolean isBlocking() {
		return blocking.get();
	}

	public void release() {
		lock.lock();
		try {
			if (blocking.compareAndSet(true, false)) {
				condition.signalAll();
			}
		} finally {
			lock.unlock();
		}
	}

	public void await() throws InterruptedException {
		lock.lock();
		try {
			while (isBlocking()) {
				condition.await();
			}
		} finally {
			lock.unlock();
		}
	}

	public void await(long time, TimeUnit unit) throws InterruptedException {
		lock.lock();
		try {
			while (isBlocking()) {
				condition.await(time, unit);
			}
		} finally {
			lock.unlock();
		}
	}
}
